package org.dromara.system.kernel;

import org.apache.commons.lang3.tuple.Pair;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.system.domain.bo.cparams.OrderPushBo.Address;
import org.dromara.system.domain.bo.cparams.OrderPushBo.Origin;

import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.encrypt.utils.EncryptUtils;
import org.dromara.system.constants.OrderConstants;
import org.dromara.system.domain.*;
import org.dromara.system.domain.bo.config.AccountBanConfig;
import org.dromara.system.domain.bo.config.ApiConfig;
import org.dromara.system.domain.bo.cparams.OrderPushBo;
import org.dromara.system.domain.bo.cparams.OrderRefundBo;
import org.dromara.system.domain.mq.OrderCallbackParam;
import org.dromara.system.domain.mq.OrderFailParam;
import org.dromara.system.domain.mq.OrderGetStatusParam;
import org.dromara.system.domain.bo.cparams.OrderUpdateBo;
import org.dromara.system.domain.mq.OrderPushParam;
import org.dromara.system.domain.vo.PayTypeVo;
import org.dromara.system.mapper.*;
import org.dromara.system.mq.OrderCallbackSender;
import org.dromara.system.mq.OrderFailSender;
import org.dromara.system.mq.OrderGetStatusSender;
import org.dromara.system.mq.OrderPushSender;
import org.dromara.system.service.*;
import org.dromara.system.utils.JwtUtils;
import org.dromara.system.utils.RequestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 订单更新核心处理
 */
@RefreshScope
@Service
@RequiredArgsConstructor
public class OrderUpdateKernel {

    private static final Logger log = LoggerFactory.getLogger(OrderUpdateKernel.class);
    private final IPayAppService payAppService;
    private final PayAppMapper payAppMapper;
    private final IPayGroupAccountService payGroupAccountService;
    private final PayOrderLogMapper orderLogMapper;
    private final PayLinkMapper payLinkMapper;
    private final RedisAlgorithmKernel redisAlgorithmKernel;
    private final IPayOrderService orderService;
    private final IPayOrderLogService orderLogService;
    private final OrderCallbackSender orderCallbackSender;
    private final IPayTypeService payTypeService;
    private final OrderGetStatusSender getStatusSender;
    private final OrderFailSender orderFailSender;
    private final OrderPushSender orderPushSender;
    private final IPayAccountService accountService;
    private final SendEmail2Kernel sendEmail2Kernel;
    private final SysUserMapper sysUserMapper;
    private final TransactionTemplate transactionTemplate;
    // 创建一个固定大小的线程池
    private static final ExecutorService executor = Executors.newFixedThreadPool(2);
    @Value("${orderCallbackTime}")
    private Integer orderCallbackTime;
    @Value("${orderPushCount}")
    private Integer orderPushCount;
    @Value("${orderPushTime}")
    private Integer orderPushTime;
    @Value("${saveFilePhpUrl}")
    private String saveFilePhpUrl;
    @Value("${openCommission}")
    private Boolean openCommission;
    private static final String[] feignArr = new String[]{"insufficient_funds", "invalid_cvc", "highest_risk_level", "Fraudulent card."};

    /**
     * 更新订单
     *
     * @param order  订单
     * @param bo     更新对象
     * @param resStr 日志内容
     * @return 结果
     */
    @Transactional
    public R<?> updateOrder(PayOrder order, OrderUpdateBo bo, String resStr) {
        PayOrderLog log = orderLogService.saveLog(null, order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "平台更新订单", resStr, null, System.currentTimeMillis());

        R<?> res;
        if (RedisUtils.tryLock("update_order_" + order.getOrderId(), 10, 10)) {
            //更新订单
            res = updateOrder(order, bo, log);
            RedisUtils.unlock("update_order_" + order.getOrderId());
        } else {
            res = R.fail("还有未执行完成的订单更新任务");
        }

        //更新日志信息
        orderLogService.updateLog(log.getLogId(), order.getOrderId(), JSONObject.toJSONString(res, JSONWriter.Feature.WriteMapNullValue), System.currentTimeMillis() - log.getTime());

        return res;
    }

    /**
     * 平台更新订单
     *
     * @param order 订单信息
     * @param bo    更新参数
     * @param log1  日志对象
     * @return 结果
     */
    @Transactional
    public R<?> updateOrder(PayOrder order, OrderUpdateBo bo, PayOrderLog log1) {

        try {
            //查询应用 可优化查询redis
            PayApp app = payAppService.selectById(order.getAppId());

            //轮询组账号配置
            PayGroupAccount groupAccount = payGroupAccountService.queryById(order.getGroupAccountId());

            //收款账号
            PayAccount account = accountService.selectById(order.getAccountId());

            //有错误消息
            if (StringUtils.isNotEmpty(bo.getError_msg())) {
                //处理是否封禁账号
                executor.submit(() -> accountBanDeal(account, bo.getError_msg()));
            }

            //订单更新对象
            PayOrder up = new PayOrder();
            up.setOrderId(order.getOrderId());

            //订单状态
            String aStatus = "";
            String aMsg = "";
            Map<String, Pair<Long, BigDecimal>> commissionMap = new HashMap<>();
            //回调的状态不为空，并且订单状态不是支付成功
            if (bo.getCode() != null && order.getStatus() != 2 && !Objects.equals(order.getIsFeign(), 1)) {
                if (bo.getCode() == 2) {
                    //首次接受到成功
                    //吃单
                    if (redisAlgorithmKernel.isFeign(app, order.getUsdMoney())) {
                        up.setIsFeign(1);//吃单状态
                        up.setStatus(3);//B端展示状态 支付失败
                        up.setRiskDetail(feignArr[new Random().nextInt(feignArr.length)]);//随机取feignArr里的一个值
                        //增加一次吃单数量
                        redisAlgorithmKernel.updateFailureCount(app);

                        aStatus = "failed";
                        aMsg = "failed";
                    } else {
                        aStatus = "success";
                        up.setStatus(2);//支付成功
                        //计算订单抽佣
                        if (openCommission) {
                            commissionMap = dealCommission(order);
                            up.setCommissionMoney(commissionMap.values().stream().map(Pair::getValue).reduce(BigDecimal.ZERO, BigDecimal::add));
                            up.setAgentCommission(commissionMap.get("agent").getValue());
                            up.setClientCommission(commissionMap.get("client").getValue());
                        }
                    }

                    //真实支付状态
                    up.setPayStatus(2);
                    //支付时间
                    up.setPayTime(DateUtils.getNowDate());
                    //成功订单总数增加
                    redisAlgorithmKernel.updateSuccessCount(app);

                    //是否推送订单到审核站
                    if (Objects.equals(account.getGenerateOrder(), 1) || Objects.equals(account.getGenerateProduct(), 1)) {
                        up.setCallback(0); //标识待回调C端
                    }
                    //如果被隐藏的，则显示出来
                    if (Objects.equals(order.getHide(), 1)) {
                        up.setHide(0);
                    }
                } else {
                    up.setStatus(bo.getCode());//支付状态
                    aStatus = "failed";
                    aMsg = bo.getFail_msg();
                }
            }

            if ("Cancel The Payment".equals(bo.getFail_msg()) && order.getStatus() != 2) {
                aStatus = "failed";
                aMsg = bo.getFail_msg();
                if (bo.getCode() == null) {
                    up.setStatus(3);
                    if (!Objects.equals(order.getIsFeign(), 1)) {
                        up.setPayStatus(3);
                    }
                }
            }

            //设置其他字段更新
            setUpdateFields(order, up, bo);

            //不是当前系统发起的退款，不更新退款相关状态
            if (up.getRefundStatus() != null && orderLogMapper.selectCount(new LambdaQueryWrapper<PayOrderLog>().eq(PayOrderLog::getOrderId, order.getOrderId()).eq(PayOrderLog::getOperate, "手动更新订单【退款状态】")) <= 0) {
                up.setRefundStatus(0);
                up.setRefundMoney(new BigDecimal("0"));
            }

            if (Objects.equals(up.getStatus(), 3)) {
                //支付时间
                up.setPayTime(DateUtils.getNowDate());
            }

            //更新订单
            long uptime = System.currentTimeMillis();
            up.setUpdateTime(DateUtils.getNowDate());
            orderService.updatePayOrderAsync(up);
            //保存请求日志
            orderLogService.saveLog(log1.getLogId(), order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "更新B端订单信息", JSONObject.toJSONString(up), "success", System.currentTimeMillis() - uptime);

            //显示支付成功/吃单 = 真实支付成功
            if (Objects.equals(up.getStatus(), 2) || (Objects.equals(up.getIsFeign(), 1) && Objects.equals(up.getStatus(), 3))) {
                //更新收款账号成功金额
                updateAccountMoney(groupAccount, order.getUsdMoney());

                //发送支付成功邮件通知
                sendEmail2Kernel.sendOrderEmail(order.getOrderId());

                if (Objects.equals(up.getCallback(), 0)) {
                    //推送订单到审核站
                    orderPushSender.sendPushMessage(new OrderPushParam(order.getOrderId(), 1), 1000L);
                }
            }

            //显示支付成功
            if (Objects.equals(up.getStatus(), 2)) {
                //更新应用成功金额
                updateAppMoney(app, order.getUsdMoney());
                //如果是短链生成的订单，处理短链过期
                updateShortLink(order.getLinkCode());
                //保存用户抽佣金额
                if (openCommission) {
                    saveUserCommission(commissionMap);
                }
            }

            //更新A端订单状态
            if (StringUtils.isNotBlank(aStatus)) {
                JSONObject json = new JSONObject();
                json.put("order_id", order.getOrderAid()); //A端订单号
                json.put("pay_status", aStatus); //A端订单状态
                json.put("pay_no", order.getOrderNo()); //B端单号
                json.put("fail_message", aMsg == null ? "" : aMsg); //支付失败原因

                //更新A端订单状态
                OrderCallbackParam param = new OrderCallbackParam();
                param.setOrderId(order.getOrderId());
                if (app != null) {
                    param.setAppSecret(app.getAppSecret());
                }
                param.setLogId(log1.getLogId());
                param.setJson(json);
                param.setCallNum(1);//回调次数
                handleOrderCallback(param);
            }

            String return_url = "";
            if (Objects.equals(up.getStatus(), 2) || Objects.equals(order.getStatus(), 2)) {
                return_url = order.getSuccessUrl();
            } else if ("Cancel The Payment".equals(bo.getFail_msg())) {
                return_url = order.getCancelUrl();
            } else {
                return_url = order.getFailureUrl();
            }
            return R.ok(new JSONObject().fluentPut("return_url", return_url));
        } catch (Exception e) {
            //保存请求日志
            orderLogService.saveLog(log1.getLogId(), order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "更新订单异常", JSONObject.toJSONString(bo), e.getMessage(), System.currentTimeMillis() - log1.getTime());

            log.error("更新订单异常", e);
            return R.fail("update order error" + e.getMessage());
        }
    }

    /**
     * 设置其他字段更新
     *
     * @param up 更新对象
     * @param bo 更新参数
     */
    private void setUpdateFields(PayOrder order, PayOrder up, OrderUpdateBo bo) {

        boolean isFeign = Objects.equals(up.getIsFeign(), 1) || Objects.equals(order.getIsFeign(), 1);

        //卡信息
        if (StringUtils.isNotEmpty(bo.getCard())) {
            up.setCardInfo(bo.getCard());
            CompletableFuture.runAsync(() -> saveCardFile(bo.getCard()));
        }

        //session_id
        if (StringUtils.isNotEmpty(bo.getSession_id())) {
            up.setSessionId(bo.getSession_id());
        }
        //平台订单号
        if (StringUtils.isNotEmpty(bo.getPayment_id())) {
            up.setOrderCid(bo.getPayment_id());
        }
        //风险级别
        if (!isFeign && StringUtils.isNotEmpty(bo.getRisk())) {
            up.setRisk(bo.getRisk());
        }
        //风险细节
        if (StringUtils.isNotEmpty(bo.getRisk_detail())) {
            up.setRiskDetail(bo.getRisk_detail());
        }
        //退款ID
        if (StringUtils.isNotEmpty(bo.getRefund_id())) {
            up.setRefundId(bo.getRefund_id());
        }
        //退款状态  退款成功后不再改退款状态
        if (bo.getRefund_code() != null && !Objects.equals(order.getRefundStatus(), 2)) {
            up.setRefundStatus(bo.getRefund_code());
            up.setRefundMoney(bo.getRefund_code() == 2 ? order.getUsdMoney() : new BigDecimal("0"));
        }
        //争议ID
        if (StringUtils.isNotEmpty(bo.getDispute_id())) {
            up.setDisputeId(bo.getDispute_id());
        }
        //争议状态
        if (bo.getDispute_code() != null) {
            up.setDisputeStatus(bo.getDispute_code());
        }
        //卡国家
        if (StringUtils.isNotEmpty(bo.getBin_country())) {
            up.setBinCountry(bo.getBin_country());
        }
        //3ds
        if (StringUtils.isNotEmpty(bo.getIs_3ds())) {
            up.setIs3ds(bo.getIs_3ds());
        }
        //缴费记录ID
        if (StringUtils.isNotEmpty(bo.getCharge_id())) {
            up.setChargeId(bo.getCharge_id());
        }
        //付款信息
        if (bo.getBuyer() != null) {
            try {
                up.setBuyer(JSONObject.toJSONString(bo.getBuyer()));
            } catch (Exception ignore) {
            }
        }
        //失败消息
        if (StringUtils.isNotEmpty(bo.getFail_msg())) {
            up.setFailMsg(bo.getFail_msg());
        }
        //支付方式名称
        if (!isFeign && StringUtils.isNotEmpty(bo.getType()) && StringUtils.isEmpty(bo.getBuild_status())) {
            up.setPayMethodType(bo.getType());
        }
        //terminal_order_sn
        if (StringUtils.isNotEmpty(bo.getTerminal_order_sn())) {
            up.setOrderSn(bo.getTerminal_order_sn());
        }
    }

    /**
     * 保存卡号文件
     *
     * @param cardStr 卡加密信息
     */
    private void saveCardFile(String cardStr) {
        String params = JwtUtils.parseInfo(cardStr);
        new RequestUtils().doPostJson(saveFilePhpUrl, params);
    }

    /**
     * 更新收款账号成功金额
     *
     * @param groupAccount 轮询组收款账号
     */
    private void updateAccountMoney(PayGroupAccount groupAccount, BigDecimal money) {
        CompletableFuture.runAsync(() -> {
            if (groupAccount != null && money != null && money.compareTo(BigDecimal.ZERO) > 0) {
                //再查询一次轮询组账号
                PayGroupAccount account = payGroupAccountService.queryById(groupAccount.getId());

                PayGroupAccount acUp = new PayGroupAccount();
                acUp.setId(account.getId());

                if (account.getTotalLimit() != null && account.getTotalLimit().compareTo(BigDecimal.ZERO) > 0) {
                    acUp.setTotalMoney(account.getTotalMoney().add(money));

                    //超过收款限额，下线收款账号
                    if (acUp.getTotalMoney().compareTo(account.getTotalLimit()) >= 0) {
                        acUp.setStatus(2);
                    }
                } else {
                    acUp.setTotalMoney(BigDecimal.ZERO);
                }

                payGroupAccountService.updateById(acUp);
            }
        });
    }

    /**
     * 更新应用成功金额
     *
     * @param app 应用
     */
    private void updateAppMoney(PayApp app, BigDecimal money) {
        CompletableFuture.runAsync(() -> {
            if (app != null && money != null && money.compareTo(BigDecimal.ZERO) > 0) {
                PayApp up = new PayApp();
                up.setAppId(app.getAppId());
                up.setSuccessTotal(app.getSuccessTotal().add(money));

                //超过收款限额，下线收款账号
                if (app.getTotalLimit() != null && app.getTotalLimit().compareTo(BigDecimal.ZERO) > 0 && up.getSuccessTotal().compareTo(app.getTotalLimit()) >= 0) {
                    up.setStatus(2);
                }
                payAppMapper.updateById(up);
            }
        });
    }

    /**
     * 处理短链过期
     *
     * @param code 短链码
     */
    private void updateShortLink(String code) {
        CompletableFuture.runAsync(() -> {
            if (StringUtils.isNotEmpty(code)) {
                LambdaUpdateWrapper<PayLink> wrapper = new LambdaUpdateWrapper<>();
                wrapper.eq(PayLink::getCode, code).eq(PayLink::getExpire, 0);
                wrapper.set(PayLink::getStatus, 2).set(PayLink::getExpireTime, DateUtils.getNowDate());
                payLinkMapper.update(wrapper);
            }
        });
    }

    /**
     * 异步回调A端订单状态
     */
    public void handleOrderCallback(OrderCallbackParam param) {
        PayOrder order = orderService.selectById(param.getOrderId());

        if (StringUtils.isEmpty(order.getCallbackUrl())) {
            return;
        }

        // 发起第一次即时通知
        long time = System.currentTimeMillis();
        String reqStr;
        try {
            Map<String, String> headers = new HashMap<>();
            String str = param.getJson().toString();
            if (StringUtils.isNotEmpty(param.getAppSecret())) {
                headers.put(OrderConstants.signature, EncryptUtils.encryptByMd5(str + param.getAppSecret()).toUpperCase(Locale.ROOT));
            }
            reqStr = new RequestUtils().doPostJsonNoTry(order.getCallbackUrl(), str, headers);
        } catch (Exception e) {
            reqStr = "回调请求失败：" + e.getMessage();
        }

        //保存请求日志
        orderLogService.saveLog(param.getLogId(), order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "更新A端订单状态", param.getJson().toString(), reqStr, System.currentTimeMillis() - time);

        Integer num = param.getCallNum();
        if (num == null) {
            num = 1;
        }

        //未接收到成功
        if (!"success".equals(reqStr) && num < 3) {
            param.setCallNum(num + 1);
            // 定时重试通知
            orderCallbackSender.sendOrderMessage(param, orderCallbackTime * 60 * 1000);
        }
    }

    /**
     * 处理订单状态回调
     *
     * @param orderId 订单ID
     */
    public void sendGetStatusHandel(Long orderId, ApiConfig config) {
        CompletableFuture.supplyAsync(() -> {
            if (config == null) {
                return R.ok();
            }
            ApiConfig.UpdateStatus statusConfig = config.getUpdateStatus();
            if (statusConfig != null && statusConfig.getCount() > 0 && statusConfig.getInterval() > 0) {
                getStatusSender.sendGetStatusMessage(new OrderGetStatusParam(orderId, 1), statusConfig.getInterval() * 60 * 1000);
            }
            return R.ok();
        });
    }

    /**
     * 主动更新订单状态
     */
    @Transactional
    public void handleGetOrderStatus(OrderGetStatusParam param) {
        PayOrder order = orderService.selectById(param.getOrderId());
        if (order == null) {
            return;
        }

        //记录请求日志
        PayOrderLog log = orderLogService.saveLog(null, order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "主动获取订单状态", JSONObject.toJSONString(param), null, System.currentTimeMillis());

        R<?> res = getOrderStatus(param, order, log);
        //更新日志信息
        orderLogService.updateLog(log.getLogId(), null, JSONObject.toJSONString(res), System.currentTimeMillis() - log.getTime());
    }

    /**
     * 获取订单状态
     *
     * @param param 参数
     * @param order 订单
     * @return 结果
     */
    @Transactional
    public R<?> getOrderStatus(OrderGetStatusParam param, PayOrder order, PayOrderLog log) {
        if (StringUtils.isEmpty(order.getCallbackUrl())) {
            return R.fail("未配置回调地址");
        }

        //收款账号
        PayAccount account = accountService.selectById(order.getAccountId());
        if (account == null) {
            return R.fail("未查询到收款账号");
        }

        //获取账号请求地址
        String baseUrl = accountService.buildRequestUrl(account);
        if (StringUtils.isEmpty(baseUrl)) {
            return R.fail("未查询到收款账号请求地址");
        }

        //请求地址
        String url = baseUrl + "query";
        if (StringUtils.isNotEmpty(account.getPlugin())) {
            url += "/";
        }

        //向平台获取订单状态
        long time = System.currentTimeMillis();
        String res = "";
        //构建参数
        JSONObject params = new JSONObject();
        params.put("terminal_order_sn", order.getOrderSn());
        params.put("checkout_id", order.getSessionId());
        try {
            //请求
            res = new RequestUtils().doPostJsonByToken(url, params.toJSONString());
        } catch (Exception e) {
            res = "【向平台获取订单状态】请求失败：" + e.getMessage();
        }
        //记录请求日志
        orderLogService.saveLog(log.getLogId(), order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "向平台获取订单状态", params.toString(JSONWriter.Feature.WriteMapNullValue), res, System.currentTimeMillis() - time);

        if (StringUtils.isEmpty(res)) {
            return R.fail("【向平台获取订单状态】返回数据为空");
        }

        //更新订单
        R<?> r = JSONObject.parseObject(res, R.class);
        if (R.isSuccess(r)) {
            OrderUpdateBo bo = (OrderUpdateBo) r.getData();
            //更新订单
            r = updateOrder(order, bo, log);
            if (R.isSuccess(r)) {
                return r;
            }
        }

        /***************如果未获取成功或更新成功，则继续发延时消息***************************/
        //获取支付平台配置
        PayTypeVo payType = payTypeService.queryById(order.getPayTypeId());
        if (payType == null) {
            return R.fail("未获取到支付平台配置");
        }
        //获取API配置
        ApiConfig config = ApiConfig.getConfig(payType.getConfig(), account.getApiType());
        if (config == null) {
            return R.fail("未获取到支付平台API配置");
        }

        //获取支付平台【主动更新状态】配置
        ApiConfig.UpdateStatus statusConfig = config.getUpdateStatus();
        if (statusConfig == null) {
            return R.fail("未获取到【主动更新状态】配置");
        }
        Integer count = statusConfig.getCount();

        Integer num = param.getCallNum();
        if (num == null) {
            num = 1;
        }

        //未接收到成功
        if (num < count) {
            param.setCallNum(num + 1);
            // 定时重试通知
            getStatusSender.sendGetStatusMessage(param, statusConfig.getInterval() * 60 * 1000);
        }
        return r;
    }

    /**
     * 处理是否封禁账号
     *
     * @param account  收款账号
     * @param errorMsg 错误消息
     */
    @Transactional
    public R<?> accountBanDeal(PayAccount account, String errorMsg) {
        if (account == null) {
            return R.ok();
        }
        PayTypeVo payType = payTypeService.queryById(account.getPayTypeId());
        if (payType == null) {
            return R.ok();
        }
        return accountBanDeal(payType, account, errorMsg);
    }

    /**
     * 处理是否封禁账号
     *
     * @param payType  支付类型
     * @param account  收款账号
     * @param errorMsg 错误消息
     */
    @Transactional
    public R<?> accountBanDeal(PayTypeVo payType, PayAccount account, String errorMsg) {
        try {
            JSONObject json = JSONObject.parseObject(StringUtils.removeComments(payType.getConfig()));
            List<AccountBanConfig> banConfigs = json.getList("accountBanConfig", AccountBanConfig.class);

            //获取对应API类型的插件地址
            String banMsg = "";
            for (AccountBanConfig banConfig : banConfigs) {
                if (Objects.equals(banConfig.getCompare(), "equal")) {
                    //等于比较
                    if (Objects.equals(errorMsg, banConfig.getError())) {
                        banMsg = errorMsg;
                        break;
                    }
                } else if (Objects.equals(banConfig.getCompare(), "contain")) {
                    //包含比较
                    if (errorMsg.contains(banConfig.getError())) {
                        banMsg = errorMsg;
                        break;
                    }
                }
            }

            //触发账号封禁关键字
            if (StringUtils.isNotEmpty(banMsg)) {
                PayAccount up = new PayAccount();
                up.setAccountId(account.getAccountId());
                up.setStatus(2);
                up.setBanMsg(banMsg);
                accountService.updateById(up);

                //收款账号禁用,则同步更新轮询组的账号禁用
                PayGroupAccount update = new PayGroupAccount();
                update.setStatus(3);
                payGroupAccountService.update(update, new LambdaUpdateWrapper<PayGroupAccount>().eq(PayGroupAccount::getAccountId, account.getAccountId()));

                //此支付方式不可用
                return R.fail("This payment method is unavailable");
            }
        } catch (Exception ignore) {
        }
        return R.ok();
    }

    /**
     * 通知平台退款
     *
     * @param order 订单
     * @return 结果
     */
    public R<OrderUpdateBo> handleRefund(PayOrder order, PayOrderLog log2, BigDecimal refundMoney) {

        try {
            //收款账号
            PayAccount account = accountService.selectById(order.getAccountId());
            if (account == null) {
                return R.fail("未查询到收款账号");
            }

            //获取账号请求地址
            String baseUrl = accountService.buildRequestUrl(account);
            if (StringUtils.isEmpty(baseUrl)) {
                return R.fail("未查询到收款账号请求地址");
            }

            String res;
            //构建参数

            OrderRefundBo bo = new OrderRefundBo(order.getOrderId(), order.getOrderCid(), null, null, order.getOrderSn(), order.getCustomerName());

            if (refundMoney != null && refundMoney.compareTo(BigDecimal.ZERO) > 0) {
                bo.setCurrency("USD");
                bo.setAmount(refundMoney);
            } else {
                //是否强制货币
                if (StringUtils.isNotEmpty(order.getForceCurrency())) {
                    bo.setCurrency(order.getForceCurrency());
                    bo.setAmount(order.getForceMoney());
                } else {
                    bo.setCurrency(order.getCurrency());
                    bo.setAmount(order.getOrderMoney());
                }
            }

            String params = JSONObject.toJSONString(bo, JSONWriter.Feature.WriteMapNullValue);
            try {
                //请求地址
                String url = baseUrl + "refund";
                if (StringUtils.isNotEmpty(account.getPlugin())) {
                    url += "/";
                }
                //请求
                res = new RequestUtils().doPostJsonByToken(url, params);
            } catch (Exception e) {
                res = "【通知平台退款】请求失败：" + e.getMessage();
            }

            orderLogService.updateLogParams(log2.getLogId(), params, res, System.currentTimeMillis() - log2.getTime());

            if (StringUtils.isEmpty(res)) {
                return R.fail("【通知平台退款】返回数据为空");
            }
            //解析返回参数
            R<?> r;
            try {
                r = JSONObject.parseObject(res, R.class);
                OrderUpdateBo updateBo = JSONObject.parseObject(r.getData().toString(), OrderUpdateBo.class);
                if (Objects.equals(updateBo.getRefund_code(), 2)) {
                    return R.ok(updateBo);
                } else {
                    return R.fail(updateBo);
                }
            } catch (Exception ignore) {
            }

            return R.fail(res);
        } catch (Exception e) {
            return R.fail("【通知平台退款】处理失败：" + e.getMessage());
        }
    }

    /**
     * 处理订单推送到审核站
     *
     * @param param
     */
    public void handleOrderPush(OrderPushParam param) {

        PayOrder order = orderService.selectById(param.getOrderId());
        if (order == null || Objects.equals(order.getCallback(), 1)) {
            return;
        }

        PayOrderLog log = null;
        int status;
        try {
            //记录请求日志
            log = orderLogService.saveLog(null, order.getOrderId(), order.getOrderNo(), order.getOrderAid(), "推送订单到审核站", null, null, System.currentTimeMillis());
            R<?> r = orderPush(order, log);

            if (R.isError(r)) {
                orderLogService.updateLogParams(log.getLogId(), null, JSONObject.toJSONString(r, JSONWriter.Feature.WriteMapNullValue), System.currentTimeMillis() - log.getTime());
                status = 2;
            } else {
                status = 1;
            }
        } catch (Exception e) {
            status = 2;
            //记录请求日志
            if (log != null) {
                orderLogService.updateLogParams(log.getLogId(), null, "【推送订单到审核站】处理异常" + e.getMessage(), System.currentTimeMillis() - log.getTime());
            }
        }

        PayOrder up = new PayOrder();
        up.setOrderId(order.getOrderId());
        up.setCallback(status);
        orderService.updatePayOrderAsync(up);

        if (status == 2 && param.getCallNum() < orderPushCount) {
            //推送失败，继续推送
            orderPushSender.sendPushMessage(new OrderPushParam(order.getOrderId(), param.getCallNum() + 1), orderPushTime * 60 * 1000);
        }
    }

    public R<?> orderPush(PayOrder order, PayOrderLog log) {

        //获取账号请求地址
        PayAccount account = accountService.selectById(order.getAccountId());
        if (account == null) {
            return R.fail("未查询到收款账号");
        }
        //推送类型
        String type = "";
        if (Objects.equals(account.getGenerateOrder(), 1) && Objects.equals(account.getGenerateProduct(), 1)) {
            type = "1";
        } else if (Objects.equals(account.getGenerateOrder(), 1)) {
            type = "2";
        } else if (Objects.equals(account.getGenerateProduct(), 1)) {
            type = "3";
        }
        if (StringUtils.isEmpty(type)) {
            return R.fail("未配置推送类型");
        }

        //获取账号请求地址
        String baseUrl = accountService.buildRequestUrl(account);
        if (StringUtils.isEmpty(baseUrl)) {
            return R.fail("未查询到收款账号请求地址");
        }

        //请求地址
        String url = baseUrl + "build";
        if (StringUtils.isNotEmpty(account.getPlugin())) {
            url += "/";
        }

        //构建参数
        OrderPushBo bo = new OrderPushBo();
        bo.setOrder_id(order.getOrderId());
        //是否强制货币
        if (StringUtils.isNotEmpty(order.getForceCurrency())) {
            bo.setCurrency(order.getForceCurrency());
            bo.setTotal(order.getForceMoney());
        } else {
            bo.setCurrency(order.getCurrency());
            bo.setTotal(order.getOrderMoney());
        }
        bo.setIp(order.getFormIp());
        bo.setPayment_id(order.getOrderCid());
        bo.setPayment_type(account.getApiType());
        bo.setType(type);
        bo.setTerminal_order_sn(order.getOrderSn());
        bo.setStatus(account.getOrderStatus());//订单状态
        //来源
        if (StringUtils.isNotEmpty(account.getOrderSource()) && Objects.equals(account.getGenerateOrder(), 1)) {
            String[] origins = account.getOrderSource().split(",");
            String ori = "";
            if (origins.length == 1) {
                ori = origins[0];
            } else if (origins.length > 1) {
                //随机取一个
                ori = origins[new Random().nextInt(origins.length)];
            }
            if (StringUtils.isNotEmpty(ori)) {
                String[] arr = ori.split("\\|");
                bo.setOrigin(new Origin(arr[0], arr.length > 1 ? arr[1] : ""));
            }
        }
        // 客户信息
        if (StringUtils.isNotEmpty(order.getCustomer())) {
            bo.setBilling(JSONObject.parseObject(order.getCustomer(), Address.class));
        }
        // 收货信息
        if (StringUtils.isNotEmpty(order.getShipping())) {
            bo.setShipping(JSONObject.parseObject(order.getShipping(), Address.class));
        }

        String params = JSONObject.toJSONString(bo, JSONWriter.Feature.WriteMapNullValue);

        //请求
        String res = new RequestUtils().doPostJsonByToken(url, params);

        //记录请求日志
        orderLogService.updateLogParams(log.getLogId(), params, res, System.currentTimeMillis() - log.getTime());

        if (StringUtils.isEmpty(res)) {
            return R.fail("【推送订单到审核站】返回数据为空");
        }

        //解析返回参数
        R<?> r;
        try {
            r = JSONObject.parseObject(res, R.class);
        } catch (Exception e) {
            return R.fail(res);
        }

        if (R.isSuccess(r) && r.getData() != null) {
            JSONObject data = (JSONObject) r.getData();
            if (data.containsKey("action_id") && data.getInteger("action_id") != null) {
                return R.ok();
            }
        }

        return r;
    }

    /**
     * 处理订单超时自动失败
     *
     * @param orderId 订单ID
     */
    public void sendOrderFail(Long orderId, ApiConfig config) {
        CompletableFuture.supplyAsync(() -> {
            if (config != null && config.getAutoFail() != null && config.getAutoFail() > 0) {
                orderFailSender.sendMessage(new OrderFailParam(orderId, 1), config.getAutoFail() * 60 * 1000);
            }
            return R.ok();
        });
    }

    /**
     * 处理订单超时失败
     *
     * @param param 参数
     */
    @Transactional
    public void handleOrderFail(OrderFailParam param) {

        PayOrder order = orderService.selectById(param.getOrderId());
        if (order == null) {
            return;
        }

        if (Objects.equals(order.getStatus(), 1)) {
            OrderUpdateBo bo = new OrderUpdateBo(order.getOrderId(), 3, "failed");
            bo.setRisk_detail("Payment timeout");
            updateOrder(order, bo, JSONObject.toJSONString(bo));
        }
    }

    /**
     * 处理订单抽佣金额
     *
     * @param order 订单
     */
    public Map<String, Pair<Long, BigDecimal>> dealCommission(PayOrder order) {

        Map<String, Pair<Long, BigDecimal>> commissionMap = new HashMap<>();
        try {
            //查询抽佣比例
            List<SysUser> users = sysUserMapper.selectList(new LambdaQueryWrapper<SysUser>().in(SysUser::getUserId, order.getAgentId(), order.getClientId()));
            for (SysUser user : users) {
                if(user.getCommissionRate().compareTo(BigDecimal.ZERO) <= 0) {
                    continue;
                }

                //计算抽佣金额
                BigDecimal money = order.getUsdMoney().multiply(user.getCommissionRate()).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
                if (money.compareTo(BigDecimal.ZERO) <= 0) {
                    continue;
                }
                commissionMap.put(user.getRoleKey(), Pair.of(user.getUserId(), money));
            }

        } catch (Exception e) {
            System.out.println("订单抽佣金额计算失败：" + e.getMessage());
        }

        return commissionMap;
    }

    /**
     * 保存用户抽佣金额
     *
     * @param commissionMap 抽佣金额
     */
    public void saveUserCommission(Map<String, Pair<Long, BigDecimal>> commissionMap) {
        if (commissionMap.isEmpty()) {
            return;
        }
        commissionMap.values().forEach( pair -> CompletableFuture.runAsync(() -> {
            // 手动管理事务
            transactionTemplate.execute(status -> {
                try {
                    Long userId = pair.getKey();
                    sysUserMapper.selectUserForUpdate(userId);
                    sysUserMapper.updateCommission(userId, pair.getValue());
                    return null; // 正常返回
                } catch (Exception e) {
                    status.setRollbackOnly(); // 手动回滚
                    System.out.println("抽佣保存失败：" + e.getMessage());
                    throw new RuntimeException(e); // 抛出异常防止继续执行
                }
            });
        }));
    }
}
